﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.OData.Routing;
using System.Web.Http.Routing;

namespace WooCoo.DataPortal.WebHost.ODataServer
{
/// <summary>OData服务路由.</summary>
    public class ODataServerRoute : HttpRoute
    {
        private static readonly string _escapedHashMark = Uri.HexEscape('#');
        private static readonly string _escapedQuestionMark = Uri.HexEscape('?');
        private bool _canGenerateDirectLink;
        /// <summary>路由前缀.</summary>
        /// <returns>The route prefix.</returns>
        public string RoutePrefix
        {
            get;
            private set;
        }
        /// <summary>构造方法.</summary>
        /// <param name="routePrefix">路由前缀.</param>
        /// <param name="pathConstraint">路径约束.</param>
        public ODataServerRoute(string routePrefix, ODataServerRouteConstraint pathConstraint)
            : this(routePrefix, pathConstraint, null, null, null, null)
        {
        }
        /// <summary>构造方法.</summary>
        /// <param name="routePrefix">路由前缀.</param>
        /// <param name="pathConstraint">路径约束.</param>
        /// <param name="defaults">The default values for the route.</param>
        /// <param name="constraints">The route constraints.</param>
        /// <param name="dataTokens">The data tokens.</param>
        /// <param name="handler">The message handler for the route.</param>
        public ODataServerRoute(string routePrefix, ODataServerRouteConstraint pathConstraint, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens, HttpMessageHandler handler)
            : base(ODataServerRoute.GetRouteTemplate(routePrefix), defaults, constraints, dataTokens, handler)
        {
            this.RoutePrefix = routePrefix;
            this._canGenerateDirectLink = (routePrefix != null && this.RoutePrefix.IndexOf('{') == -1);
            if (pathConstraint != null)
            {
                base.Constraints.Add(ODataRouteConstants.ConstraintName, pathConstraint);
            }
        }
        private static string GetRouteTemplate(string prefix)
        {
            if (!string.IsNullOrEmpty(prefix))
            {
                return prefix + '/' + ODataRouteConstants.ODataPathTemplate;
            }
            return ODataRouteConstants.ODataPathTemplate;
        }
        /// <summary>根据<paramref name="values"/>和路由计算url.</summary>
        /// <returns>The retrieved <see cref="T:System.Web.Http.Routing.IHttpVirtualPathData" />.</returns>
        /// <param name="request">The request message.</param>
        /// <param name="values">The values.</param>
        public override IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values)
        {
            object obj;
            if (values != null && values.Keys.Contains(HttpRoute.HttpRouteKey, StringComparer.OrdinalIgnoreCase) && values.TryGetValue(ODataRouteConstants.ODataPath, out obj))
            {
                string text = obj as string;
                if (text != null)
                {
                    return this.GenerateLinkDirectly(request, text) ?? base.GetVirtualPath(request, values);
                }
            }
            return null;
        }
        internal HttpVirtualPathData GenerateLinkDirectly(HttpRequestMessage request, string odataPath)
        {
            HttpConfiguration configuration = request.GetConfiguration();
            if (configuration != null && this._canGenerateDirectLink)
            {
                string text = ODataServerRoute.CombinePathSegments(this.RoutePrefix, odataPath);
                text = ODataServerRoute.UriEncode(text);
                return new HttpVirtualPathData(this, text);
            }
            return null;
        }
        private static string CombinePathSegments(string routePrefix, string odataPath)
        {
            if (string.IsNullOrEmpty(routePrefix))
            {
                return odataPath;
            }
            if (!string.IsNullOrEmpty(odataPath))
            {
                return routePrefix + '/' + odataPath;
            }
            return routePrefix;
        }
        private static string UriEncode(string str)
        {
            string text = Uri.EscapeUriString(str);
            text = text.Replace("#", ODataServerRoute._escapedHashMark);
            return text.Replace("?", ODataServerRoute._escapedQuestionMark);
        }
    }
}
